import Vec3 from "./vec3";
import Mat3 from "./Mat3";
import Quat from "./quat";

export default class Transform {
    constructor() {
        this.elements=new Float64Array(12);
        this.elements[0]=0;
        this.elements[1]=0;
        this.elements[2]=0;
        this.elements[3]=1;
        this.elements[4]=0;
        this.elements[5]=0;
        this.elements[6]=0;
        this.elements[7]=1;
        this.elements[8]=0;
        this.elements[9]=0;
        this.elements[10]=0;
        this.elements[11]=1;
    }
    get _positionX(){
        return this.elements[0];
    }
    set _positionX(n){
        this.elements[0]=n;
    }
    get _positionY(){
        return this.elements[1];
    }
    set _positionY(n){
        this.elements[1]=n;
    }
    get _positionZ(){
        return this.elements[2];
    }
    set _positionZ(n){
        this.elements[2]=n;
    }
    get _rotation00(){
        return this.elements[3];
    }
    set _rotation00(n){
        this.elements[3]=n;
    }
    get _rotation01(){
        return this.elements[4];
    }
    set _rotation01(n){
        this.elements[4]=n;
    }
    get _rotation02(){
        return this.elements[5];
    }
    set _rotation02(n){
        this.elements[5]=n;
    }
    get _rotation10(){
        return this.elements[6];
    }
    set _rotation10(n){
        this.elements[6]=n;
    }
    get _rotation11(){
        return this.elements[7];
    }
    set _rotation11(n){
        this.elements[7]=n;
    }
    get _rotation12(){
        return this.elements[8];
    }
    set _rotation12(n){
        this.elements[8]=n;
    }
    get _rotation20(){
        return this.elements[9];
    }
    set _rotation20(n){
        this.elements[9]=n;
    }
    get _rotation21(){
        return this.elements[10];
    }
    set _rotation21(n){
        this.elements[10]=n;
    }
    get _rotation22(){
        return this.elements[11];
    }
    set _rotation22(n){
        this.elements[11]=n;
    }

    identity() {
        let _this=this.elements;
        _this[0] = 0;_this[1] = 0;_this[2] = 0;
        _this[3] = 1;_this[4] = 0;_this[5] = 0;
        _this[6] = 0;_this[7] = 1;_this[8] = 0;
        _this[9] = 0;_this[10] = 0;_this[11] = 1;
        return this;
    }
    getPosition() {
        let position = new Vec3();
        let es=position.elements,_this=this.elements;
        es[0] = _this[0];es[1] = _this[1];es[2] = _this[2];
        return position;
    }
    getPositionTo(position) {
        let es=position.elements,_this=this.elements;
        es[0] = _this[0];es[1] = _this[1];es[2] = _this[2];
    }
    setPosition(position) {
        let es=position.elements,_this=this.elements;
        _this[0] = es[0];_this[1] = es[1];_this[2] = es[2];
        return this;
    }
    translate(translation) {
        let te=translation.elements,_this=this.elements;
        let diffX = te[0],diffY = te[1],diffZ = te[2];
        _this[0] += diffX;_this[1] += diffY;_this[2] += diffZ;
    }
    rotate(_rotation) {
        let rotation=_rotation.elements,_this=this.elements;
        let rot00 = rotation[0],rot01 = rotation[1],rot02 = rotation[2];
        let rot10 = rotation[3],rot11 = rotation[4],rot12 = rotation[5];
        let rot20 = rotation[6],rot21 = rotation[7],rot22 = rotation[8];
        let __tmp__00;
        let __tmp__01;
        let __tmp__02;
        let __tmp__10;
        let __tmp__11;
        let __tmp__12;
        let __tmp__20;
        let __tmp__21;
        let __tmp__22;
        __tmp__00 = rot00 * _this[3] + rot01 * _this[6] + rot02 * _this[9];
        __tmp__01 = rot00 * _this[4] + rot01 * _this[7] + rot02 * _this[10];
        __tmp__02 = rot00 * _this[5] + rot01 * _this[8] + rot02 * _this[11];
        __tmp__10 = rot10 * _this[3] + rot11 * _this[6] + rot12 * _this[9];
        __tmp__11 = rot10 * _this[4] + rot11 * _this[7] + rot12 * _this[10];
        __tmp__12 = rot10 * _this[5] + rot11 * _this[8] + rot12 * _this[11];
        __tmp__20 = rot20 * _this[3] + rot21 * _this[6] + rot22 * _this[9];
        __tmp__21 = rot20 * _this[4] + rot21 * _this[7] + rot22 * _this[10];
        __tmp__22 = rot20 * _this[5] + rot21 * _this[8] + rot22 * _this[11];
        _this[3] = __tmp__00;
        _this[4] = __tmp__01;
        _this[5] = __tmp__02;
        _this[6] = __tmp__10;
        _this[7] = __tmp__11;
        _this[8] = __tmp__12;
        _this[9] = __tmp__20;
        _this[10] = __tmp__21;
        _this[11] = __tmp__22;
    }
    getOrientationTo(orientation) {
        let iqX;
        let iqY;
        let iqZ;
        let iqW;
        let e00 = this._rotation00;
        let e11 = this._rotation11;
        let e22 = this._rotation22;
        let t = e00 + e11 + e22;
        let s;
        if(t > 0) {
            s = Math.sqrt(t + 1);
            iqW = 0.5 * s;
            s = 0.5 / s;
            iqX = (this._rotation21 - this._rotation12) * s;
            iqY = (this._rotation02 - this._rotation20) * s;
            iqZ = (this._rotation10 - this._rotation01) * s;
        } else if(e00 > e11) {
            if(e00 > e22) {
                s = Math.sqrt(e00 - e11 - e22 + 1);
                iqX = 0.5 * s;
                s = 0.5 / s;
                iqY = (this._rotation01 + this._rotation10) * s;
                iqZ = (this._rotation02 + this._rotation20) * s;
                iqW = (this._rotation21 - this._rotation12) * s;
            } else {
                s = Math.sqrt(e22 - e00 - e11 + 1);
                iqZ = 0.5 * s;
                s = 0.5 / s;
                iqX = (this._rotation02 + this._rotation20) * s;
                iqY = (this._rotation12 + this._rotation21) * s;
                iqW = (this._rotation10 - this._rotation01) * s;
            }
        } else if(e11 > e22) {
            s = Math.sqrt(e11 - e22 - e00 + 1);
            iqY = 0.5 * s;
            s = 0.5 / s;
            iqX = (this._rotation01 + this._rotation10) * s;
            iqZ = (this._rotation12 + this._rotation21) * s;
            iqW = (this._rotation02 - this._rotation20) * s;
        } else {
            s = Math.sqrt(e22 - e00 - e11 + 1);
            iqZ = 0.5 * s;
            s = 0.5 / s;
            iqX = (this._rotation02 + this._rotation20) * s;
            iqY = (this._rotation12 + this._rotation21) * s;
            iqW = (this._rotation10 - this._rotation01) * s;
        }
        orientation.x = iqX;
        orientation.y = iqY;
        orientation.z = iqZ;
        orientation.w = iqW;
    }
    setOrientation(quaternion) {
        let qX;
        let qY;
        let qZ;
        let qW;
        qX = quaternion.x;
        qY = quaternion.y;
        qZ = quaternion.z;
        qW = quaternion.w;
        let x = qX;
        let y = qY;
        let z = qZ;
        let w = qW;
        let x2 = 2 * x;
        let y2 = 2 * y;
        let z2 = 2 * z;
        let xx = x * x2;
        let yy = y * y2;
        let zz = z * z2;
        let xy = x * y2;
        let yz = y * z2;
        let xz = x * z2;
        let wx = w * x2;
        let wy = w * y2;
        let wz = w * z2;
        this._rotation00 = 1 - yy - zz;
        this._rotation01 = xy - wz;
        this._rotation02 = xz + wy;
        this._rotation10 = xy + wz;
        this._rotation11 = 1 - xx - zz;
        this._rotation12 = yz - wx;
        this._rotation20 = xz - wy;
        this._rotation21 = yz + wx;
        this._rotation22 = 1 - xx - yy;
        return this;
    }
    clone() {
        let tf = new Transform();
        tf._positionX = this._positionX;
        tf._positionY = this._positionY;
        tf._positionZ = this._positionZ;
        tf._rotation00 = this._rotation00;
        tf._rotation01 = this._rotation01;
        tf._rotation02 = this._rotation02;
        tf._rotation10 = this._rotation10;
        tf._rotation11 = this._rotation11;
        tf._rotation12 = this._rotation12;
        tf._rotation20 = this._rotation20;
        tf._rotation21 = this._rotation21;
        tf._rotation22 = this._rotation22;
        return tf;
    }
    copyFrom(transform) {
        this._positionX = transform._positionX;
        this._positionY = transform._positionY;
        this._positionZ = transform._positionZ;
        this._rotation00 = transform._rotation00;
        this._rotation01 = transform._rotation01;
        this._rotation02 = transform._rotation02;
        this._rotation10 = transform._rotation10;
        this._rotation11 = transform._rotation11;
        this._rotation12 = transform._rotation12;
        this._rotation20 = transform._rotation20;
        this._rotation21 = transform._rotation21;
        this._rotation22 = transform._rotation22;
        return this;
    }
    getRotation() {
        let rotation = new Mat3();
        rotation.e00 = this._rotation00;
        rotation.e01 = this._rotation01;
        rotation.e02 = this._rotation02;
        rotation.e10 = this._rotation10;
        rotation.e11 = this._rotation11;
        rotation.e12 = this._rotation12;
        rotation.e20 = this._rotation20;
        rotation.e21 = this._rotation21;
        rotation.e22 = this._rotation22;
        return rotation;
    }
    getRotationTo(out) {
        out.e00 = this._rotation00;
        out.e01 = this._rotation01;
        out.e02 = this._rotation02;
        out.e10 = this._rotation10;
        out.e11 = this._rotation11;
        out.e12 = this._rotation12;
        out.e20 = this._rotation20;
        out.e21 = this._rotation21;
        out.e22 = this._rotation22;
    }
    setRotation(rotation) {
        this._rotation00 = rotation.e00;
        this._rotation01 = rotation.e01;
        this._rotation02 = rotation.e02;
        this._rotation10 = rotation.e10;
        this._rotation11 = rotation.e11;
        this._rotation12 = rotation.e12;
        this._rotation20 = rotation.e20;
        this._rotation21 = rotation.e21;
        this._rotation22 = rotation.e22;
        return this;
    }
    setRotationXyz(eulerAngles) {
        let xyzX;
        let xyzY;
        let xyzZ;
        xyzX = eulerAngles.x;
        xyzY = eulerAngles.y;
        xyzZ = eulerAngles.z;
        let sx = Math.sin(xyzX);
        let sy = Math.sin(xyzY);
        let sz = Math.sin(xyzZ);
        let cx = Math.cos(xyzX);
        let cy = Math.cos(xyzY);
        let cz = Math.cos(xyzZ);
        this._rotation00 = cy * cz;
        this._rotation01 = -cy * sz;
        this._rotation02 = sy;
        this._rotation10 = cx * sz + cz * sx * sy;
        this._rotation11 = cx * cz - sx * sy * sz;
        this._rotation12 = -cy * sx;
        this._rotation20 = sx * sz - cx * cz * sy;
        this._rotation21 = cz * sx + cx * sy * sz;
        this._rotation22 = cx * cy;
    }
    rotateXyz(eulerAngles) {
        let xyzX;
        let xyzY;
        let xyzZ;
        let rot00;
        let rot01;
        let rot02;
        let rot10;
        let rot11;
        let rot12;
        let rot20;
        let rot21;
        let rot22;
        xyzX = eulerAngles.x;
        xyzY = eulerAngles.y;
        xyzZ = eulerAngles.z;
        let sx = Math.sin(xyzX);
        let sy = Math.sin(xyzY);
        let sz = Math.sin(xyzZ);
        let cx = Math.cos(xyzX);
        let cy = Math.cos(xyzY);
        let cz = Math.cos(xyzZ);
        rot00 = cy * cz;
        rot01 = -cy * sz;
        rot02 = sy;
        rot10 = cx * sz + cz * sx * sy;
        rot11 = cx * cz - sx * sy * sz;
        rot12 = -cy * sx;
        rot20 = sx * sz - cx * cz * sy;
        rot21 = cz * sx + cx * sy * sz;
        rot22 = cx * cy;
        let __tmp__00;
        let __tmp__01;
        let __tmp__02;
        let __tmp__10;
        let __tmp__11;
        let __tmp__12;
        let __tmp__20;
        let __tmp__21;
        let __tmp__22;
        __tmp__00 = rot00 * this._rotation00 + rot01 * this._rotation10 + rot02 * this._rotation20;
        __tmp__01 = rot00 * this._rotation01 + rot01 * this._rotation11 + rot02 * this._rotation21;
        __tmp__02 = rot00 * this._rotation02 + rot01 * this._rotation12 + rot02 * this._rotation22;
        __tmp__10 = rot10 * this._rotation00 + rot11 * this._rotation10 + rot12 * this._rotation20;
        __tmp__11 = rot10 * this._rotation01 + rot11 * this._rotation11 + rot12 * this._rotation21;
        __tmp__12 = rot10 * this._rotation02 + rot11 * this._rotation12 + rot12 * this._rotation22;
        __tmp__20 = rot20 * this._rotation00 + rot21 * this._rotation10 + rot22 * this._rotation20;
        __tmp__21 = rot20 * this._rotation01 + rot21 * this._rotation11 + rot22 * this._rotation21;
        __tmp__22 = rot20 * this._rotation02 + rot21 * this._rotation12 + rot22 * this._rotation22;
        this._rotation00 = __tmp__00;
        this._rotation01 = __tmp__01;
        this._rotation02 = __tmp__02;
        this._rotation10 = __tmp__10;
        this._rotation11 = __tmp__11;
        this._rotation12 = __tmp__12;
        this._rotation20 = __tmp__20;
        this._rotation21 = __tmp__21;
        this._rotation22 = __tmp__22;
    }
    getOrientation() {
        let q = new Quat();
        let iqX;
        let iqY;
        let iqZ;
        let iqW;
        let e00 = this._rotation00;
        let e11 = this._rotation11;
        let e22 = this._rotation22;
        let t = e00 + e11 + e22;
        let s;
        if(t > 0) {
            s = Math.sqrt(t + 1);
            iqW = 0.5 * s;
            s = 0.5 / s;
            iqX = (this._rotation21 - this._rotation12) * s;
            iqY = (this._rotation02 - this._rotation20) * s;
            iqZ = (this._rotation10 - this._rotation01) * s;
        } else if(e00 > e11) {
            if(e00 > e22) {
                s = Math.sqrt(e00 - e11 - e22 + 1);
                iqX = 0.5 * s;
                s = 0.5 / s;
                iqY = (this._rotation01 + this._rotation10) * s;
                iqZ = (this._rotation02 + this._rotation20) * s;
                iqW = (this._rotation21 - this._rotation12) * s;
            } else {
                s = Math.sqrt(e22 - e00 - e11 + 1);
                iqZ = 0.5 * s;
                s = 0.5 / s;
                iqX = (this._rotation02 + this._rotation20) * s;
                iqY = (this._rotation12 + this._rotation21) * s;
                iqW = (this._rotation10 - this._rotation01) * s;
            }
        } else if(e11 > e22) {
            s = Math.sqrt(e11 - e22 - e00 + 1);
            iqY = 0.5 * s;
            s = 0.5 / s;
            iqX = (this._rotation01 + this._rotation10) * s;
            iqZ = (this._rotation12 + this._rotation21) * s;
            iqW = (this._rotation02 - this._rotation20) * s;
        } else {
            s = Math.sqrt(e22 - e00 - e11 + 1);
            iqZ = 0.5 * s;
            s = 0.5 / s;
            iqX = (this._rotation02 + this._rotation20) * s;
            iqY = (this._rotation12 + this._rotation21) * s;
            iqW = (this._rotation10 - this._rotation01) * s;
        }
        q.x = iqX;
        q.y = iqY;
        q.z = iqZ;
        q.w = iqW;
        return q;
    }
}